
/*
 *  Copyright t lefering, David Given
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *  These are the four essential freedoms with GNU GPL software:
 *  1: freedom to run the program, for any purpose
 *  2: freedom to study how the program works, and change it to make it do what you wish
 *  3: freedom to redistribute copies to help your Free Software friends
 *  4: freedom to distribute copies of your modified versions to your Free Software friends
 *   ,           ,
 *  /             \
 * ((__-^^-,-^^-__))
 * `-_---'  `---_-'
 *  `--|o`   'o|--'
 *      \  `  /
 *       ): :(
 *       :o_o:
 *        "-"
 */

#ifndef GLOBALS_H
#define GLOBALS_H 1

#define _GNU_SOURCE

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "lib.h"
#include "linearize.h"
#include "expression.h"
#include "storage.h"
#include "flow.h"
#include "liveness.h"

#include "avl.h"

#define assert(x) do { if(!(x)) { printf("file %s %s() assert at line %d for source line %d\n",__FILE__,__func__,__LINE__,cur_insn_line); } } while(0)

#define NUM_REGS 1024*16
#define MAX_ARGS 1024

/* Available output buffers. */

enum {
	ZBUFFER_STDOUT = -1,
	ZBUFFER_CODE = 0,
	ZBUFFER_FUNCTION,
	ZBUFFER_FUNCTIONCODE,
	ZBUFFER_HEADER,
	ZBUFFER_INITIALIZER,
	ZBUFFER__MAX
};

enum {
	TYPE_NONE = 0,
	TYPE_ANY,
	TYPE_VOID,
	TYPE_INT,
	TYPE_FLOAT,
	TYPE_PTR,
	TYPE_FNPTR,
	TYPE_FN,
	TYPE_STRUCT,
};

enum {
	REGTYPE_INT = 1 << 0,
	REGTYPE_FLOAT = 1 << 1,
	REGTYPE_BOOL = 1 << 2,
	REGTYPE_OPTR = 1 << 3,
	REGTYPE_FPTR = 1 << 4,

	REGTYPE_ALL = (1 << 5) - 1,
	NUM_REG_CLASSES = 5
};

/* Special register classes. */

enum {
	REGCLASS_VOID = -1,
	REGCLASS_REGPAIR = -2
};

struct bb_state {
	struct position pos;
	struct storage_hash_list *inputs;
	struct storage_hash_list *outputs;
	struct storage_hash_list *internal;
};

struct hardreg {
	char *name;
	unsigned int busy:16;
	unsigned int number:8;
	unsigned int regclass:8;
	unsigned int used:1;
	unsigned int touched:1;
	unsigned int dying:1;
};

/* Represents a reference to a hardreg or register pair. */

struct hardregref {
	int type;
	struct hardreg *simple;
	struct hardreg *base;	/* Valid if type == TYPE_PTR */
};

/* pinfos store the backend-specific data about a pseudo: notably,
 * what the C type is (int, float etc), and what register it's currently
 * stored in. Note that just to make life more exciting, a given hardreg
 * may store several pseudos at once (in the phi case).
 */

struct pinfo {
	pseudo_t pseudo;
	int type;
	int size;
	struct hardregref reg;
	struct hardregref wire;
	unsigned int stackoffset;
	unsigned int dying:1;
	unsigned int stacked:1;
};

struct sinfo {
	struct symbol *sym;	/* sparse symbol */
	char *name;		/* mangled name */
	unsigned int here:1;	/* is this symbol defined in this file? */
	unsigned int declared:1;	/* has this symbol been declared? */
	unsigned int defined:1;	/* has this symbol been defined? */
	unsigned int anonymous:1;	/* is this symbol anonymous? */
};

//struct pinfo;

DECLARE_PTR_LIST(pinfo_list, struct pinfo);

struct binfo {
	struct basic_block *bb;
	int id;			/* sequence number for this bb */
};

struct codegenerator {
	int pointer_zero_offset;
	const char *spname;
	const char *fpname;
	const char *stackname;
	int register_class[NUM_REG_CLASSES];

	void (*reset_registers)(void);
	void (*init_register)(struct hardreg * reg, int regclass);
	const char *(*get_register_name)(struct hardreg * reg);

	void (*prologue)(void);
	void (*epilogue)(void);
	void (*comment)(const char *format, ...);

	void (*declare_function)(struct symbol * sym, int returning);
	void (*declare_function_arg)(int regclass);
	void (*declare_function_vararg)(void);
	void (*declare_function_end)(void);

	void (*declare_slot)(struct symbol * sym, unsigned size);
	void (*create_storage)(struct symbol * sym, unsigned size);
	void (*import)(struct symbol * sym);
	void (*export)(struct symbol * sym);

	/* These functions will always be called in order (_arg and _reg may
	 * be called multiple times).
	 */
	void (*function_prologue)(struct symbol * name, int returning);
	void (*function_prologue_arg)(struct hardreg * reg);
	void (*function_prologue_vararg)(void);
	void (*function_prologue_reg)(struct hardreg * reg);
	void (*function_prologue_end)(void);

	void (*function_epilogue)(void);

	void (*bb_start)(struct binfo * bb);
	void (*bb_end_jump)(struct binfo * target);
	void (*bb_end_if_arith)(struct hardreg * cond, struct binfo * truetarget, struct binfo * falsetarget);
	void (*bb_end_if_ptr)(struct hardreg * cond, struct binfo * truetarget, struct binfo * falsetarget);

	void (*copy)(struct hardreg * src, struct hardreg * dest);
	void (*load)(struct hardreg * simple, struct hardreg * base, int offset, struct hardreg * dest);
	void (*store)(struct hardreg * simple, struct hardreg * base, int offset, struct hardreg * src);

	void (*set_int)(long long int value, struct hardreg * dest);
	void (*set_float)(long double value, struct hardreg * dest);
	void (*set_osymbol)(struct symbol * sym, struct hardreg * dest);
	void (*set_fsymbol)(struct symbol * sym, struct hardreg * dest);

	void (*toint)(struct hardreg * src, struct hardreg * dest);
	void (*negate)(struct hardreg * src, struct hardreg * dest);
	void (*add)(struct hardreg * src1, struct hardreg * src2, struct hardreg * dest);
	void (*subtract)(struct hardreg * src1, struct hardreg * src2, struct hardreg * dest);
	void (*multiply)(struct hardreg * src1, struct hardreg * src2, struct hardreg * dest);
	void (*divide)(struct hardreg * src1, struct hardreg * src2, struct hardreg * dest);
	void (*mod)(struct hardreg * src1, struct hardreg * src2, struct hardreg * dest);
	void (*shl)(struct hardreg * src1, struct hardreg * src2, struct hardreg * dest);
	void (*shr)(struct hardreg * src1, struct hardreg * src2, struct hardreg * dest);
	void (*logand)(struct hardreg * src1, struct hardreg * src2, struct hardreg * dest);
	void (*logor)(struct hardreg * src1, struct hardreg * src2, struct hardreg * dest);
	void (*logxor)(struct hardreg * src1, struct hardreg * src2, struct hardreg * dest);
	void (*booland)(struct hardreg * src1, struct hardreg * src2, struct hardreg * dest);
	void (*boolor)(struct hardreg * src1, struct hardreg * src2, struct hardreg * dest);
	void (*set_gt)(struct hardreg * src1, struct hardreg * src2, struct hardreg * dest);
	void (*set_ge)(struct hardreg * src1, struct hardreg * src2, struct hardreg * dest);
	void (*set_lt)(struct hardreg * src1, struct hardreg * src2, struct hardreg * dest);
	void (*set_le)(struct hardreg * src1, struct hardreg * src2, struct hardreg * dest);
	void (*set_eq)(struct hardreg * src1, struct hardreg * src2, struct hardreg * dest);
	void (*set_ne)(struct hardreg * src1, struct hardreg * src2, struct hardreg * dest);

	void (*select_arith)(struct hardreg * cond,
			     struct hardreg * dest1, struct hardreg * dest2,
			     struct hardreg * true1, struct hardreg * true2, struct hardreg * false1, struct hardreg * false2);
	void (*select_ptr)(struct hardreg * cond,
			   struct hardreg * dest1, struct hardreg * dest2,
			   struct hardreg * true1, struct hardreg * true2, struct hardreg * false1, struct hardreg * false2);

	/* These are always called in order (okay, one call_returning(), followed
	 * by zero or more call_reg(), followed by call_end()).
	 */
	void (*call)(struct hardreg * func, struct hardreg * dest1, struct hardreg * dest2);
	void (*call_arg)(struct hardreg * arg);
	void (*call_vararg)(struct hardreg * arg);
	void (*call_end)(void);

	void (*ret)(struct hardreg * simple, struct hardreg * base);

	void (*memcpyimpl)(struct hardregref * src, struct hardregref * dest, int size);
};

extern const struct codegenerator *cg;
extern const struct codegenerator cg_javascript;
extern const struct codegenerator cg_java;
extern struct symbol_list *all_syms;

extern struct hardreg stackbase_reg;
extern struct hardreg stackoffset_reg;
extern struct hardreg frameoffset_reg;
extern struct hardreg hardregs[NUM_REGS];

extern int cur_insn_line;
extern unsigned int unique;
extern FILE *outputstream;

extern void compile_symbol_list(struct symbol_list *list);
extern int get_base_type_of_symbol(struct symbol *s);
extern int lookup_base_type_of_pseudo(pseudo_t pseudo);
extern int get_base_type_of_pseudo(pseudo_t pseudo);
extern void reset_pinfo(void);
extern struct pinfo *lookup_pinfo_of_pseudo(pseudo_t pseudo);
extern void init_register_allocator(void);
extern char *show_hardreg(struct hardreg *reg);
extern char *show_hardregref(struct hardregref *hrf);
extern void reset_hardregs(void);
extern void untouch_hardregs(void);
extern int find_regclass_for_returntype(int type);
extern int find_regclass_for_regtype(int regtype);
extern struct hardreg *allocate_hardreg(int regtype);
extern void find_hardregref(struct hardregref *hrf, pseudo_t pseudo);
extern void create_hardregref(struct hardregref *hrf, pseudo_t pseudo);
extern void clone_ptr_hardregref(struct hardregref *src, struct hardregref *hrf, pseudo_t pseudo);
extern void ref_hardregref(struct hardregref *hrf);
extern void unref_hardreg(struct hardreg *reg);
extern void put_pseudo_in_hardregref(pseudo_t pseudo, struct hardregref *hrf);
extern void mark_pseudo_as_dying(pseudo_t pseudo);
extern void kill_dying_pseudos(void);
extern void wire_up_bb_recursively(struct basic_block *bb, unsigned long generation, int *sequence);
extern int is_pseudo_in_register(pseudo_t pseudo);
extern void get_binfo_list(struct binfo ***list, int *count);
extern void reset_binfo(void);
extern struct binfo *lookup_binfo_of_basic_block(struct basic_block *bb);
extern void generate_ep(struct entrypoint *ep);
extern void dump_bb(struct basic_block *bb);
extern void rewrite_bb_recursively(struct basic_block *bb, unsigned long generation);
extern void emit_initializer(void);
extern void sparse_output_symdata(struct symbol *sym);
extern void graph(void);
extern void zsetbuffer(int buffer);
extern void zflush(int buffer);

extern struct sinfo *lookup_sinfo_of_symbol(struct symbol *sym);
extern char *show_symbol_mangled(struct symbol *sym);
extern char *aprintf(const char *fmt, ...);
extern void zprintf(const char *format, ...);
extern void zvprintf(const char *format, va_list ap);

#endif

/* end */
